"""
权限管理服务层
处理用户、角色、权限的管理业务逻辑
"""

from typing import List, Optional, Dict, Any
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, and_, or_, func, delete
from sqlalchemy.orm import selectinload
from fastapi import HTTPException, status

from app.models.auth import User, Role, Permission, UserRole, RolePermission
from app.schemas.auth import (
    UserCreate, UserUpdate, UserResponse, UserListResponse,
    RoleCreate, RoleUpdate, RoleResponse, RoleListResponse,
    PermissionCreate, PermissionUpdate, PermissionResponse, PermissionListResponse,

)
from app.core.security import get_password_hash
from app.core.logger import logger
from app.utils.timezone_utils import get_shanghai_now
from datetime import datetime


class PermissionService:
    """权限管理服务类"""
    
    def __init__(self):
        pass
    
    # ============ 用户管理 ============
    
    async def create_user(
        self, 
        db: AsyncSession, 
        user_data: UserCreate,
        current_user: User
    ) -> UserResponse:
        """创建用户"""
        try:
            # 检查用户名是否已存在
            stmt = select(User).where(User.username == user_data.username)
            result = await db.execute(stmt)
            if result.scalar_one_or_none():
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="用户名已存在"
                )
            
            # 检查邮箱是否已存在
            stmt = select(User).where(User.email == user_data.email)
            result = await db.execute(stmt)
            if result.scalar_one_or_none():
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="邮箱已被注册"
                )
            
            # 创建用户
            user = User(
                username=user_data.username,
                email=user_data.email,
                password_hash=get_password_hash(user_data.password),
                full_name=user_data.full_name,
                phone=user_data.phone,
                department=user_data.department,
                position=user_data.position,
                password_changed_at=get_shanghai_now()
            )
            
            db.add(user)
            await db.flush()  # 获取用户ID
            
            # 分配角色
            if user_data.role_ids:
                for role_id in user_data.role_ids:
                    # 验证角色是否存在
                    stmt = select(Role).where(Role.id == role_id)
                    result = await db.execute(stmt)
                    role = result.scalar_one_or_none()
                    if not role:
                        raise HTTPException(
                            status_code=status.HTTP_400_BAD_REQUEST,
                            detail=f"角色ID {role_id} 不存在"
                        )
                    
                    user_role = UserRole(
                        user_id=user.id,
                        role_id=role_id,
                        assigned_by=current_user.id,
                        assigned_at=get_shanghai_now()
                    )
                    db.add(user_role)
            
            await db.commit()
            
            # 操作日志功能已移除
            
            # 重新查询用户以获取完整信息，预加载所有必要的关系
            stmt = select(User).where(User.id == user.id).options(
                selectinload(User.user_roles).selectinload(UserRole.role).selectinload(Role.role_permissions).selectinload(RolePermission.permission)
            )
            result = await db.execute(stmt)
            user = result.scalar_one()
            
            logger.info(f"用户创建成功：{user.username} (by {current_user.username})")
            return UserResponse.from_orm(user)
            
        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"创建用户异常：{str(e)}")
            await db.rollback()
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="创建用户失败"
            )
    
    async def update_user(
        self, 
        db: AsyncSession, 
        user_id: int, 
        user_data: UserUpdate,
        current_user: User
    ) -> UserResponse:
        """更新用户"""
        try:
            # 查找用户，预加载所有必要的关系
            stmt = select(User).where(User.id == user_id).options(
                selectinload(User.user_roles).selectinload(UserRole.role).selectinload(Role.role_permissions).selectinload(RolePermission.permission)
            )
            result = await db.execute(stmt)
            user = result.scalar_one_or_none()
            
            if not user:
                raise HTTPException(
                    status_code=status.HTTP_404_NOT_FOUND,
                    detail="用户不存在"
                )
            
            # 检查邮箱是否被其他用户使用
            if user_data.email and user_data.email != user.email:
                stmt = select(User).where(
                    and_(User.email == user_data.email, User.id != user_id)
                )
                result = await db.execute(stmt)
                if result.scalar_one_or_none():
                    raise HTTPException(
                        status_code=status.HTTP_400_BAD_REQUEST,
                        detail="邮箱已被其他用户使用"
                    )
            
            # 更新用户信息
            update_data = user_data.dict(exclude_unset=True)
            role_ids = update_data.pop('role_ids', None)
            
            for field, value in update_data.items():
                setattr(user, field, value)
            
            # 更新角色分配
            if role_ids is not None:
                # 删除现有角色分配
                stmt = delete(UserRole).where(UserRole.user_id == user_id)
                await db.execute(stmt)
                
                # 添加新的角色分配
                for role_id in role_ids:
                    # 验证角色是否存在
                    stmt = select(Role).where(Role.id == role_id)
                    result = await db.execute(stmt)
                    role = result.scalar_one_or_none()
                    if not role:
                        raise HTTPException(
                            status_code=status.HTTP_400_BAD_REQUEST,
                            detail=f"角色ID {role_id} 不存在"
                        )
                    
                    user_role = UserRole(
                        user_id=user_id,
                        role_id=role_id,
                        assigned_by=current_user.id,
                        assigned_at=get_shanghai_now()
                    )
                    db.add(user_role)
            
            user.updated_at = get_shanghai_now()
            await db.commit()
            
            # 操作日志功能已移除
            
            # 重新查询用户以获取完整信息，预加载所有必要的关系
            stmt = select(User).where(User.id == user_id).options(
                selectinload(User.user_roles).selectinload(UserRole.role).selectinload(Role.role_permissions).selectinload(RolePermission.permission)
            )
            result = await db.execute(stmt)
            user = result.scalar_one()
            
            logger.info(f"用户更新成功：{user.username} (by {current_user.username})")
            return UserResponse.from_orm(user)
            
        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"更新用户异常：{str(e)}")
            await db.rollback()
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="更新用户失败"
            )
    
    async def delete_user(
        self, 
        db: AsyncSession, 
        user_id: int,
        current_user: User
    ) -> Dict[str, str]:
        """删除用户"""
        try:
            # 查找用户
            stmt = select(User).where(User.id == user_id)
            result = await db.execute(stmt)
            user = result.scalar_one_or_none()
            
            if not user:
                raise HTTPException(
                    status_code=status.HTTP_404_NOT_FOUND,
                    detail="用户不存在"
                )
            
            # 不能删除自己
            if user_id == current_user.id:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="不能删除自己的账户"
                )
            
            # 不能删除超级用户（除非自己也是超级用户）
            if user.is_superuser and not current_user.is_superuser:
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail="无权删除超级用户"
                )
            
            username = user.username
            await db.delete(user)
            await db.commit()
            
            # 操作日志功能已移除
            
            logger.info(f"用户删除成功：{username} (by {current_user.username})")
            return {"message": f"用户 {username} 删除成功"}
            
        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"删除用户异常：{str(e)}")
            await db.rollback()
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="删除用户失败"
            )
    
    async def get_user_list(
        self, 
        db: AsyncSession, 
        page: int = 1, 
        page_size: int = 10,
        search: Optional[str] = None,
        role_id: Optional[int] = None,
        is_active: Optional[bool] = None
    ) -> UserListResponse:
        """获取用户列表"""
        try:
            # 构建查询条件
            conditions = []
            
            if search:
                conditions.append(
                    or_(
                        User.username.contains(search),
                        User.email.contains(search),
                        User.full_name.contains(search)
                    )
                )
            
            if is_active is not None:
                conditions.append(User.is_active == is_active)
            
            if role_id:
                conditions.append(
                    User.user_roles.any(
                        and_(UserRole.role_id == role_id, UserRole.is_active == True)
                    )
                )
            
            # 查询总数
            count_stmt = select(func.count(User.id))
            if conditions:
                count_stmt = count_stmt.where(and_(*conditions))
            
            result = await db.execute(count_stmt)
            total = result.scalar()
            
            # 查询用户列表，预加载所有必要的关系
            stmt = select(User).options(
                selectinload(User.user_roles).selectinload(UserRole.role).selectinload(Role.role_permissions).selectinload(RolePermission.permission)
            )
            
            if conditions:
                stmt = stmt.where(and_(*conditions))
            
            stmt = stmt.offset((page - 1) * page_size).limit(page_size)
            stmt = stmt.order_by(User.created_at.desc())
            
            result = await db.execute(stmt)
            users = result.scalars().all()
            
            return UserListResponse(
                users=[UserResponse.from_orm(user) for user in users],
                total=total,
                page=page,
                page_size=page_size,
                total_pages=(total + page_size - 1) // page_size
            )
            
        except Exception as e:
            logger.error(f"获取用户列表异常：{str(e)}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="获取用户列表失败"
            )
    
    # ============ 角色管理 ============
    
    async def create_role(
        self, 
        db: AsyncSession, 
        role_data: RoleCreate,
        current_user: User
    ) -> RoleResponse:
        """创建角色"""
        try:
            # 检查角色名是否已存在
            stmt = select(Role).where(Role.name == role_data.name)
            result = await db.execute(stmt)
            if result.scalar_one_or_none():
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="角色名已存在"
                )
            
            # 创建角色
            role = Role(
                name=role_data.name,
                display_name=role_data.display_name,
                description=role_data.description
            )
            
            db.add(role)
            await db.flush()  # 获取角色ID
            
            # 分配权限
            if role_data.permission_ids:
                for permission_id in role_data.permission_ids:
                    # 验证权限是否存在
                    stmt = select(Permission).where(Permission.id == permission_id)
                    result = await db.execute(stmt)
                    permission = result.scalar_one_or_none()
                    if not permission:
                        raise HTTPException(
                            status_code=status.HTTP_400_BAD_REQUEST,
                            detail=f"权限ID {permission_id} 不存在"
                        )
                    
                    role_permission = RolePermission(
                        role_id=role.id,
                        permission_id=permission_id,
                        granted_by=current_user.id,
                        granted_at=get_shanghai_now()
                    )
                    db.add(role_permission)
            
            await db.commit()
            
            # 操作日志功能已移除
            
            # 重新查询角色以获取完整信息
            stmt = select(Role).where(Role.id == role.id).options(
                selectinload(Role.role_permissions).selectinload(RolePermission.permission)
            )
            result = await db.execute(stmt)
            role = result.scalar_one()
            
            logger.info(f"角色创建成功：{role.name} (by {current_user.username})")
            return RoleResponse.from_orm(role)

        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"创建角色异常：{str(e)}")
            await db.rollback()
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="创建角色失败"
            )

    # ============ 权限管理 ============

    async def create_permission(
        self,
        db: AsyncSession,
        permission_data: PermissionCreate,
        current_user: User
    ) -> PermissionResponse:
        """创建权限"""
        try:
            # 检查权限名是否已存在
            stmt = select(Permission).where(Permission.name == permission_data.name)
            result = await db.execute(stmt)
            if result.scalar_one_or_none():
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="权限名已存在"
                )

            # 创建权限
            permission = Permission(
                name=permission_data.name,
                display_name=permission_data.display_name,
                description=permission_data.description,
                resource=permission_data.resource,
                action=permission_data.action,
                is_system=False  # 用户创建的权限都是非系统权限
            )

            db.add(permission)
            await db.commit()

            # 操作日志功能已移除

            logger.info(f"权限创建成功：{permission.name} (by {current_user.username})")
            return PermissionResponse.from_orm(permission)

        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"创建权限异常：{str(e)}")
            await db.rollback()
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="创建权限失败"
            )

    async def get_permission(
        self,
        db: AsyncSession,
        permission_id: int
    ) -> PermissionResponse:
        """获取权限详情"""
        try:
            stmt = select(Permission).where(Permission.id == permission_id)
            result = await db.execute(stmt)
            permission = result.scalar_one_or_none()

            if not permission:
                raise HTTPException(
                    status_code=status.HTTP_404_NOT_FOUND,
                    detail="权限不存在"
                )

            return PermissionResponse.from_orm(permission)

        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"获取权限详情异常：{str(e)}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="获取权限详情失败"
            )

    async def update_permission(
        self,
        db: AsyncSession,
        permission_id: int,
        permission_data: PermissionUpdate,
        current_user: User
    ) -> PermissionResponse:
        """更新权限"""
        try:
            stmt = select(Permission).where(Permission.id == permission_id)
            result = await db.execute(stmt)
            permission = result.scalar_one_or_none()

            if not permission:
                raise HTTPException(
                    status_code=status.HTTP_404_NOT_FOUND,
                    detail="权限不存在"
                )

            # 系统权限不允许修改核心字段
            if permission.is_system:
                # 只允许修改显示名称和描述
                allowed_fields = {'display_name', 'description'}
                update_data = permission_data.dict(exclude_unset=True)
                for field in update_data:
                    if field not in allowed_fields:
                        raise HTTPException(
                            status_code=status.HTTP_400_BAD_REQUEST,
                            detail=f"系统权限不允许修改字段: {field}"
                        )

            # 更新权限信息
            update_data = permission_data.dict(exclude_unset=True)
            for field, value in update_data.items():
                setattr(permission, field, value)

            permission.updated_at = get_shanghai_now()
            await db.commit()

            # 操作日志功能已移除

            logger.info(f"权限更新成功：{permission.name} (by {current_user.username})")
            return PermissionResponse.from_orm(permission)

        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"更新权限异常：{str(e)}")
            await db.rollback()
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="更新权限失败"
            )

    async def delete_permission(
        self,
        db: AsyncSession,
        permission_id: int,
        current_user: User
    ):
        """删除权限"""
        try:
            stmt = select(Permission).where(Permission.id == permission_id)
            result = await db.execute(stmt)
            permission = result.scalar_one_or_none()

            if not permission:
                raise HTTPException(
                    status_code=status.HTTP_404_NOT_FOUND,
                    detail="权限不存在"
                )

            # 系统权限不允许删除
            if permission.is_system:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="系统权限不允许删除"
                )

            permission_name = permission.name
            await db.delete(permission)
            await db.commit()

            # 操作日志功能已移除

            logger.info(f"权限删除成功：{permission_name} (by {current_user.username})")

        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"删除权限异常：{str(e)}")
            await db.rollback()
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="删除权限失败"
            )

    async def assign_permission_to_roles(
        self,
        db: AsyncSession,
        permission_id: int,
        role_ids: List[int],
        current_user: User
    ):
        """分配权限给角色"""
        try:
            # 验证权限是否存在
            stmt = select(Permission).where(Permission.id == permission_id)
            result = await db.execute(stmt)
            permission = result.scalar_one_or_none()

            if not permission:
                raise HTTPException(
                    status_code=status.HTTP_404_NOT_FOUND,
                    detail="权限不存在"
                )

            # 验证角色是否存在
            for role_id in role_ids:
                stmt = select(Role).where(Role.id == role_id)
                result = await db.execute(stmt)
                role = result.scalar_one_or_none()
                if not role:
                    raise HTTPException(
                        status_code=status.HTTP_400_BAD_REQUEST,
                        detail=f"角色ID {role_id} 不存在"
                    )

            # 为每个角色分配权限
            for role_id in role_ids:
                # 检查是否已经分配过
                stmt = select(RolePermission).where(
                    and_(
                        RolePermission.role_id == role_id,
                        RolePermission.permission_id == permission_id
                    )
                )
                result = await db.execute(stmt)
                existing = result.scalar_one_or_none()

                if not existing:
                    role_permission = RolePermission(
                        role_id=role_id,
                        permission_id=permission_id,
                        granted_by=current_user.id,
                        granted_at=get_shanghai_now()
                    )
                    db.add(role_permission)
                elif not existing.is_active:
                    # 如果存在但未激活，则激活它
                    existing.is_active = True
                    existing.granted_by = current_user.id
                    existing.granted_at = get_shanghai_now()

            await db.commit()

            # 操作日志功能已移除

            logger.info(f"权限分配成功：{permission.name} -> {role_ids} (by {current_user.username})")

        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"权限分配异常：{str(e)}")
            await db.rollback()
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="权限分配失败"
            )

    # ============ 辅助方法 ============



    async def get_resources(self, db: AsyncSession) -> List[str]:
        """获取所有资源类型"""
        try:
            stmt = select(Permission.resource).distinct()
            result = await db.execute(stmt)
            resources = result.scalars().all()
            return sorted(resources)

        except Exception as e:
            logger.error(f"获取资源类型异常：{str(e)}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="获取资源类型失败"
            )

    async def get_resource_actions(self, db: AsyncSession, resource: str) -> List[str]:
        """获取指定资源的所有操作类型"""
        try:
            stmt = select(Permission.action).where(Permission.resource == resource).distinct()
            result = await db.execute(stmt)
            actions = result.scalars().all()
            return sorted(actions)

        except Exception as e:
            logger.error(f"获取资源操作异常：{str(e)}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="获取资源操作失败"
            )
